#pragma once

#include <vector>

namespace ann{

	struct TrainData
	{
		TrainData() {}
		TrainData(std::vector<unsigned int> &_p_inData, std::vector<unsigned int> &_p_result)
		{
			_s_inData = _p_inData;
			_s_result = _p_result;
		}
		std::vector<unsigned int> _s_inData;
		std::vector<unsigned int> _s_result;
	};

    typedef std::vector< TrainData > TrainDataList;
    typedef std::vector< unsigned int > uVector;
    typedef std::vector< double > dVector;

    class InputNode;
    class BPNode;
    class OutputNode;
    class Tube;

class BPNet
{
public:
	BPNet( const unsigned int _num_in  = 2,
           const unsigned int _num_bp  = 2,
           const unsigned int _num_out = 1,
           const double _alpha         = 0.6,
           const double _p_criEk       = 0.008,
           const unsigned int p_itrLmt = 8000
         );
	virtual ~BPNet(void);

	bool	Init            ();
	bool	Reset           ();
	void	Tick            ();
	bool	IsConverged     () const ;
	bool	Train           ();
	bool	PushTrainData   ( const TrainData _tData );

	bool	InputData       ( const std::vector<unsigned int> &_p_inData );
	dVector	GetResult       () const ;
	
private:
    void    Update_W        ( const unsigned int _p_trainIdx );
    void    CalEk           ( const unsigned int p_trainIdx );
	bool	TestConverge    ();
    
    //usage: set -1, when one is not related in the idx calculation
#   define UNRELATED_IDX -1
    unsigned int    GetTubeIDX( const unsigned int _p_outNode_id,
                                const unsigned int _p_bpNode_id,
                                const unsigned int _p_inNode_id
                              );


private:
	bool					m_isInited;
	bool					m_isConverged;
    unsigned int            m_itrCnt;

    unsigned int            m_cnt_trainData;
	TrainDataList		    m_trainData;
    double*                 m_ek;
    double                  m_criEk;
    double                  m_criEk_double;
    unsigned int            m_itrLmt;
    
    double                  m_alpha;
    unsigned int            m_cnt_tube;
    unsigned int            m_cnt_valveTube;
    unsigned int            m_cnt_inNode;
    unsigned int            m_cnt_bpNode;
    unsigned int            m_cnt_outNode;

    Tube*                   m_tubeList;
    Tube*                   m_valveTubeList;
	InputNode*              m_inNodeList;
	OutputNode*             m_outNodeList;
	BPNode*                 m_bpNodeList;
};

}
